home *** CD-ROM | disk | FTP | other *** search
/ SGI Developer Toolbox 6.1 / SGI Developer Toolbox 6.1 - Disc 4.iso / public / bit / src / forms / FORMS / draw.c < prev    next >
C/C++ Source or Header  |  1994-08-01  |  19KB  |  654 lines

  1. /*
  2.  * draw.c
  3.  *
  4.  * This file is part of the basis of the Forms Library
  5.  *
  6.  * It contains lowlevel routines to draw boxes, text, etc. These routines
  7.  * are used by the object drawing routines for objects.
  8.  *
  9.  * Written by Mark Overmars
  10.  *
  11.  * Version 2.2 a
  12.  * Date: Jun 21, 1993
  13.  */
  14.  
  15. #include <malloc.h>
  16. #include <stdio.h>
  17. #include "gl/gl.h"
  18. #include "gl/device.h"
  19. #include "fmclient.h"
  20. #include <string.h>
  21. #include "forms.h"
  22.  
  23. /*********
  24.    Mouse stuff.
  25. *********/
  26.  
  27. void fl_get_mouse(float *xx,float *yy)
  28. /* returns the position of the mouse in world coordinates*/
  29. {
  30.   long x,y;
  31.   getorigin(&x,&y);
  32.   *xx = (float) (getvaluator(MOUSEX)-x);
  33.   *yy = (float) (getvaluator(MOUSEY)-y);
  34. }
  35.  
  36. /*********
  37.    Clipping.
  38. *********/
  39.  
  40. void fl_set_clipping(float x,float y,float w,float h)
  41. /* Sets the clipping region */
  42. {
  43.   Screencoord sl,sr,sb,st;
  44.   sl = (short) (x);
  45.   sr = (short) (sl + w - 1.0);
  46.   sb = (short) (y);
  47.   st = (short) (sb + h - 1.0);
  48.   scrmask(sl,sr,sb,st);
  49. }
  50.  
  51. void fl_unset_clipping()
  52. /* Resets the clipping region */
  53. {
  54.   Screencoord sl,sr,sb,st;
  55.   getviewport(&sl,&sr,&sb,&st);
  56.   scrmask(sl,sr,sb,st);
  57. }
  58.  
  59. /*********
  60.    Font related stuff
  61. *********/
  62.  
  63. typedef struct {
  64.   int        defined;    /* Whether the font is defined */
  65.   char         name[64];    /* Name of the font */
  66.   int         fnumb;        /* Number of sizes in use */
  67.   float     size[32];    /* different sizes in use */
  68.   fmfonthandle     fhandle[32];    /* handles for different sizes */
  69. } FL_FONT;
  70.  
  71. static FL_FONT fl_font[FL_MAXFONT];    /* The fonts used */
  72.  
  73. static fmfonthandle use_font(int numb, float size)
  74. /* Returns the handle to font numb in the required size. */
  75. {
  76.   int i;
  77.   /* Error checking */
  78.   if (numb < 0 || numb >= FL_MAXFONT)
  79.   {
  80.     fl_error("use_font","Trying to use non-existing font");
  81.     return use_font(0,FL_NORMAL_FONT);
  82.   }
  83.   if (!fl_font[numb].defined)
  84.   {
  85.     fl_error("use_font","Trying to use undefined font");
  86.     return use_font(0,FL_NORMAL_FONT);
  87.   }
  88.   /* Create  basic font if required */
  89.   if (fl_font[numb].fnumb == 0)
  90.   {
  91.     fl_font[numb].fhandle[0] = fmfindfont(fl_font[numb].name);
  92.     /* Check whether existing */
  93.     if (fl_font[numb].fhandle[0] == NULL)
  94.       fl_font[numb].fhandle[0] = fmfindfont(fl_font[0].name);
  95.     fl_font[numb].fnumb = 1;
  96.   }
  97.   /* Search for the required size. */
  98.   for (i=1; i<fl_font[numb].fnumb; i++)
  99.     if (size == fl_font[numb].size[i])
  100.       return fl_font[numb].fhandle[i];
  101.   /* If not available, create it */
  102.   if (fl_font[numb].fnumb == 32) 
  103.   {
  104.     fmfreefont(fl_font[numb].fhandle[31]);
  105.     fl_font[numb].fnumb--;
  106.   }
  107.   fl_font[numb].size[fl_font[numb].fnumb] = size;
  108.   fl_font[numb].fhandle[fl_font[numb].fnumb] = 
  109.         fmscalefont(fl_font[numb].fhandle[0],size);
  110.   fl_font[numb].fnumb++;
  111.   return fl_font[numb].fhandle[fl_font[numb].fnumb-1];
  112. }
  113.  
  114. void fl_set_font_name(int numb, char name[])
  115. /* Sets the name of a particular font number. */
  116. {
  117.   int i;
  118.   if (numb < 0 || numb >= FL_MAXFONT)
  119.   {
  120.     fl_error("fl_set_font_name","Setting name of non-existing font number.");
  121.     return;
  122.   }
  123.   if (fl_font[numb].defined)
  124.     for (i=0; i < fl_font[numb].fnumb; i++)
  125.       fmfreefont(fl_font[numb].fhandle[i]);
  126.   fl_font[numb].defined = TRUE;
  127.   strcpy(fl_font[numb].name,name);
  128.   fl_font[numb].fnumb = 0;
  129. }
  130.  
  131. void fl_set_font(char normalname[], char boldname[],
  132.         char italicname[], char fixedname[])
  133. /* Old style setting routine. WILL BE REMOVED IN THE FUTURE. */
  134. {
  135.   fl_set_font_name(0,normalname);
  136.   fl_set_font_name(1,boldname);
  137.   fl_set_font_name(2,italicname);
  138.   fl_set_font_name(3,fixedname);
  139. }
  140.  
  141. void fl_init_fonts()
  142. /* Initializes the fonts being used to the defaults */
  143. {
  144.   int i;
  145.   for (i=0; i<FL_MAXFONT;i++) fl_font[i].defined = FALSE;
  146.   fminit();
  147.   fl_set_font_name(0,FL_FONT_NAME_0);
  148.   fl_set_font_name(1,FL_FONT_NAME_1);
  149.   fl_set_font_name(2,FL_FONT_NAME_2);
  150.   fl_set_font_name(3,FL_FONT_NAME_3);
  151.   fl_set_font_name(4,FL_FONT_NAME_4);
  152.   fl_set_font_name(5,FL_FONT_NAME_5);
  153.   fl_set_font_name(6,FL_FONT_NAME_6);
  154.   fl_set_font_name(7,FL_FONT_NAME_7);
  155.   fl_set_font_name(8,FL_FONT_NAME_8);
  156.   fl_set_font_name(9,FL_FONT_NAME_9);
  157.   fl_set_font_name(10,FL_FONT_NAME_10);
  158.   fl_set_font_name(11,FL_FONT_NAME_11);
  159.   fl_set_font_name(12,FL_FONT_NAME_12);
  160.   fl_set_font_name(13,FL_FONT_NAME_13);
  161.   fl_set_font_name(14,FL_FONT_NAME_14);
  162.   fl_set_font_name(15,FL_FONT_NAME_15);
  163. }
  164.  
  165. float fl_get_char_height(float size, int style)
  166. /* returns the height of the current font in size points */
  167. {
  168.   fmfontinfo info;
  169.   fmfonthandle fnt = use_font(style,size);
  170.   if (fnt == NULL) return 0.0;
  171.   fmgetfontinfo(fnt,&info);
  172.   return (float) info.height;
  173. }
  174.  
  175. float fl_get_string_width(float size, int style, char str[])
  176. /* returns the width of the given string */
  177. {
  178.   fmfontinfo info;
  179.   fmfonthandle fnt = use_font(style,size);
  180.   if (fnt == NULL) return 0.0;
  181.   fmgetfontinfo(fnt,&info);
  182.   return (float) fmgetstrwidth(fnt,str);
  183. }
  184.  
  185. float fl_get_char_width(float size, int style, char ch)
  186. /* returns the width of the given character */
  187. {
  188.   char str[2];
  189.   str[0] = ch; str[1] = '\0';
  190.   return fl_get_string_width(size,style,str);
  191. }
  192.  
  193. /*********
  194.    Color Stuff.
  195. *********/
  196.  
  197. static short fl_red[4096], fl_green[4096], fl_blue[4096];
  198.  
  199. void fl_init_colormap()
  200. {
  201.   long cmwin;
  202.   int i;
  203.   /* Read colormap colors into internal table */
  204.   fl_save_user_window();
  205.   noport();
  206.   cmwin = winopen("CM");
  207.   for (i=0; i<4096; i++)
  208.     {fl_red[i] = 0; fl_green[i] = 0; fl_blue[i] = 0; }
  209.   for (i=0; i<256; i++)
  210.     getmcolor(i,&fl_red[i],&fl_green[i],&fl_blue[i]);
  211.   winclose(cmwin);
  212.   fl_restore_user_window();
  213.   /* Correct colors for small number of bitplanes */
  214.   if (getgdesc(GD_BITS_NORM_DBL_RED) <= 4)
  215.     for (i=0; i<256; i++)
  216.     {
  217.        fl_red[i] = 8 * (fl_red[i] / 8);
  218.        fl_green[i] = 8 * (fl_green[i] / 8);
  219.        fl_blue[i] = 8 * (fl_blue[i] / 8);
  220.     }
  221. }
  222.  
  223. void fl_color(int col)
  224. /* Sets a colormap index in RGB mode. */
  225. {
  226.   if (fl_rgbmode)
  227.     RGBcolor(fl_red[col],fl_green[col],fl_blue[col]);
  228.   else
  229.     color(col);
  230. }
  231.  
  232. void fl_mapcolor(int i, short red, short green, short blue)
  233. /* Changes a colormap index */
  234. {
  235.   if (fl_rgbmode)
  236.     { fl_red[i] = red; fl_green[i] = green; fl_blue[i] = blue;}
  237.   else
  238.     mapcolor(i,red,green,blue);
  239. }
  240.  
  241. void fl_getmcolor(int i, short *red, short *green, short *blue)
  242. /* Returns a colormap index */
  243. {
  244.   if (fl_rgbmode)
  245.     {*red = fl_red[i]; *green = fl_green[i]; *blue = fl_blue[i];}
  246.   else
  247.     getmcolor(i,red,green,blue);
  248. }
  249.  
  250. /*********
  251.    Drawing boxes.
  252. *********/
  253.  
  254. static void vv(float x,float y)
  255.   { short v[2] ; v[0] = (short) x; v[1] = (short) y; v2s(v);}
  256.  
  257. void fl_line(float x, float y, float w, float h, int col)
  258. /* Draws a line in the given color. */
  259. {
  260.   fl_color(col);
  261.   bgnline(); vv(x,y); vv(x+w-1.0,y+h-1.0); endline();
  262. }
  263.  
  264. void fl_rect(float x, float y, float w, float h, int col)
  265. /* Draws a rectangle in the given color. */
  266. {
  267.   fl_color(col);
  268.   bgnpolygon();
  269.     vv(x,y); vv(x+w,y); vv(x+w,y+h); vv(x,y+h);
  270.   endpolygon();
  271. }
  272.  
  273. void fl_bound(float x, float y, float w, float h, int col)
  274. /* Draws a boundary in the given color. */
  275. {
  276.   fl_color(col);
  277.   bgnclosedline();
  278.     vv(x,y); vv(x+w-1.,y); vv(x+w-1.,y+h-1.); vv(x,y+h-1.);
  279.   endclosedline();
  280. }
  281.  
  282. void fl_rectbound(float x, float y, float w, float h, int col)
  283. /* Draws a rectangle in the given color with a black boundary. */
  284. {
  285.   fl_color(col);
  286.   bgnpolygon();
  287.     vv(x+1.,y+1.); vv(x+w-1.,y+1.); vv(x+w-1.,y+h-1.); vv(x+1.,y+h-1.);
  288.   endpolygon();
  289.   fl_color(0);
  290.   bgnclosedline();
  291.     vv(x,y); vv(x+w-1.,y); vv(x+w-1.,y+h-1.); vv(x,y+h-1.);
  292.   endclosedline();
  293. }
  294.  
  295. #define RN    5
  296. #define RS    15.0
  297.  
  298. static float offset[RN] = { 0.0, 0.07612, 0.29289, 0.61732, 1.0};
  299.  
  300. static void rbox(int fill, float x,float y,float w,float h)
  301. /* Draws a rounded box */
  302. {
  303.   int i;
  304.   float rsx ,rsy, rs;
  305.   rsx = 0.4*w; rsy = 0.4*h;
  306.   if (rsx > rsy) rs = rsy; else  rs = rsx;
  307.   if (rs > RS) rs = RS;
  308.   rsx = rs; rsy = rs;
  309.  
  310.   if (fill) bgnpolygon(); else bgnclosedline();
  311.     for (i=0; i<RN; i++)
  312.        vv(x + offset[RN-i-1]*rsx, y + offset[i] * rsy);
  313.     for (i=0; i<RN; i++)
  314.        vv(x + offset[i]*rsx, y + h-1.0 - offset[RN-i-1] * rsy);
  315.     for (i=0; i<RN; i++)
  316.        vv(x + w-1.0 - offset[RN-i-1]*rsx, y + h-1.0 - offset[i] * rsy);
  317.     for (i=0; i<RN; i++)
  318.        vv(x + w-1.0 - offset[i]*rsx, y + offset[RN-i-1] * rsy);
  319.   if (fill) endpolygon(); else endclosedline();
  320. }
  321.  
  322. void fl_drw_box(int style,float x,float y,float w,float h,int c,float bw)
  323. /* Draws a box. */
  324. {
  325.   if (style == FL_NO_BOX) return;
  326.   switch (style)
  327.   {
  328.     case FL_ROUNDED_BOX:
  329.       fl_color(c); rbox(1,x,y,w,h);
  330.       fl_color(0); rbox(0,x,y,w,h);
  331.       break;
  332.     case FL_RFLAT_BOX:
  333.       fl_color(c); rbox(1,x,y,w,h);
  334.       break;
  335.     case FL_RSHADOW_BOX:
  336.       /* draw the shadow */
  337.       fl_color(FL_RIGHT_BOUND_COL);
  338.       fl_set_clipping(x+bw,y-bw,w,bw+2.0);
  339.       rbox(1,x+bw,y-bw,w,h);
  340.       fl_set_clipping(x+w-1.0,y,bw+1.0,h-bw);
  341.       rbox(1,x+bw,y-bw,w,h);
  342.       fl_set_clipping(x+w+bw-RS,y,RS,RS);
  343.       rbox(1,x+bw,y-bw,w,h);
  344.       fl_unset_clipping();
  345.       /* draw the box */
  346.       fl_color(c); rbox(1,x,y,w,h);
  347.       fl_color(0); rbox(0,x,y,w,h);
  348.       break;
  349.     case FL_FRAME_BOX:
  350.       fl_rect(x+2.,y+2.,w-4.,h-4.,c);
  351.       fl_bound(x+1.,y,w-1.,h-1.,FL_LEFT_BOUND_COL);
  352.       fl_color(FL_RIGHT_BOUND_COL);
  353.       bgnline(); vv(x,y); vv(x,y+h-1.); vv(x+w-1.,y+h-1.); endline();
  354.       bgnline(); vv(x+2.,y+1.);vv(x+w-2.,y+1.);vv(x+w-2.,y+h-3.); endline();
  355.       break;
  356.     case FL_BORDER_BOX:
  357.       fl_rectbound(x,y,w,h,c); break;
  358.     case FL_FLAT_BOX:
  359.       fl_rect(x,y,w,h,c); break;
  360.     case FL_SHADOW_BOX:
  361.       fl_rect(x+bw,y-bw,w,bw,FL_RIGHT_BOUND_COL);
  362.       fl_rect(x+w,y-bw,bw,h,FL_RIGHT_BOUND_COL);
  363.       fl_rectbound(x,y,w,h,c);
  364.       break;
  365.     case FL_UP_BOX:
  366.       fl_rect(x+bw+1.,y+bw+1.,w-2*bw-2.,h-2*bw-2.,c);
  367.       fl_rect(x+1.,y+h-bw-1.,w-2.,bw,FL_TOP_BOUND_COL);
  368.       fl_rect(x+1.,y+1.,w-2.,bw,FL_BOT_BOUND_COL);
  369.       fl_color(FL_RIGHT_BOUND_COL);
  370.       bgnpolygon();
  371.         vv(x+w-bw-1.,y+bw+1.); vv(x+w-bw-1.,y+h-bw-1.);
  372.         vv(x+w-1.,y+h-1.); vv(x+w-1.,y+1.);
  373.       endpolygon();
  374.       fl_color(FL_LEFT_BOUND_COL);
  375.       bgnpolygon();
  376.         vv(x+1.,y+1.); vv(x+1.,y+h-1.);
  377.         vv(x+bw+1.,y+h-bw-1.); vv(x+bw+1.,y+bw+1.);
  378.       endpolygon();
  379.       fl_bound(x,y,w,h,0);
  380.       break;
  381.     case FL_DOWN_BOX:
  382.       fl_rectbound(x+bw,y+bw,w-2*bw,h-2*bw,c);
  383.       fl_rect(x,y+h-bw,w,bw,FL_BOT_BOUND_COL);
  384.       fl_rect(x,y,w,bw,FL_TOP_BOUND_COL);
  385.       fl_color(FL_LEFT_BOUND_COL);
  386.       bgnpolygon();
  387.       vv(x+w-bw,y+bw); vv(x+w-bw,y+h-bw); vv(x+w,y+h); vv(x+w,y);
  388.       endpolygon();
  389.       fl_color(FL_RIGHT_BOUND_COL);
  390.       bgnpolygon();
  391.         vv(x,y); vv(x,y+h); vv(x+bw,y+h-bw); vv(x+bw,y+bw);
  392.       endpolygon();
  393.       break;
  394.     default:
  395.       fl_error("fl_draw_box","Unknown box type");
  396.       break;
  397.   }
  398. }
  399.  
  400. /*********
  401.    Drawing text.
  402. *********/
  403.  
  404. #define NL    10
  405.  
  406. /***
  407.   Major text drawing routine
  408.  ***/
  409.  
  410. void fl_drw_string(
  411.   int horalign,        /* Horizontal alignment -1=left, 0=center, 1=right */
  412.   int vertalign,    /* Vertical alignment -1=bottom, 0=center, 1=top */
  413.   float x, float y, float w, float h,    /* Bounding box */
  414.   int clip,        /* Whether to clip to bounding box */
  415.   int backcol,        /* Background color */
  416.   int forecol,        /* Foreground color (text color) */
  417.   int curscol,        /* Cursor color */
  418.   float size,        /* Font size */
  419.   int style,        /* Font style */
  420.   int curspos,        /* The cursor position (-1 = no cursor) */
  421.   int selstart,int selend,  /* The selected region (end<start = no region) */
  422.   char str[])        /* The (muli-line) string */
  423. {
  424.   int i;        /* counter */
  425.   char tc;        /* temporary character */
  426.   float tt;        /* temp value */
  427.   char *lines[1024];    /* pointers to the start of the different lines */
  428.   int start[1024];    /* start position of these lines */
  429.   float startx[1024];    /* start x-coordinate of these lines */
  430.   float starty[1024];    /* start y-coordinate of these lines */
  431.   float width[1024];    /* string width of the lines */
  432.   int lnumb;        /* number of lines */
  433.   fmfonthandle fnt;    /* font to be used */
  434.   fmfontinfo info;    /* info of the font */
  435.   float height;        /* height of the font */
  436.   float desc;        /* descender of the font */
  437.   int slstart,slend;    /* Temporary selection positions */
  438.   float xsel,wsel;    /* position and width of selection area */
  439.  
  440.   /* Check whether anything has to be done */
  441.   if (curspos != 0 && (str == NULL || str[0] == '\0')) return;
  442.  
  443.   /* Set the font to be used and get some info */
  444.   fnt = use_font(style,size);
  445.   if (fnt == NULL) return;
  446.   fmsetfont(fnt);
  447.   fmgetfontinfo(fnt,&info);
  448.   height = info.ysize;
  449.   desc = info.yorig;
  450.  
  451.   /* Set clipping if required */
  452.   if (clip) fl_set_clipping(x,y,w,h);
  453.  
  454.   /* Split string into lines */
  455.   lines[0] = &(str[0]);
  456.   start[0] = 0;
  457.   lnumb = 1;
  458.   for (i = 0; str[i] != '\0'; i++)
  459.     if (str[i] == NL)
  460.     {
  461.       str[i] = '\0';
  462.       lines[lnumb] = &(str[i+1]);
  463.       start[lnumb] = i+1;
  464.       lnumb++;
  465.     }
  466.   start[lnumb] = i+1;
  467.  
  468.   /* Calculate start coordinates of lines */
  469.   for (i = 0; i < lnumb; i++)
  470.   {
  471.     width[i] = fmgetstrwidth(fnt,lines[i]);
  472.     if (horalign == -1) startx[i] = x;
  473.     if (horalign == 0)  startx[i] = x + 0.5*(w-width[i]);
  474.     if (horalign == 1)  startx[i] = x + w - width[i];
  475.     if (vertalign == -1)  starty[i] = y - (i - lnumb)*height;
  476.     if (vertalign == 0)  starty[i] = y + 0.5*h - (i - 0.5*lnumb)*height;
  477.     if (vertalign == 1) starty[i] = y + h - i*height;
  478.   }
  479.  
  480.   /* Draw the lines */
  481.   for (i = 0; i < lnumb; i++)
  482.   {
  483.     /* Check whether visible */
  484.     if (clip && starty[i]-height > y+h) continue;
  485.     if (clip && starty[i] < y) break;
  486.     /* Draw it */
  487.     cmov2(startx[i],starty[i]-height+desc);
  488.     fl_color(forecol);
  489.     fmprstr(lines[i]);
  490.     /* Draw selection area if required. */
  491.     if (selstart < start[i+1] && selend >start[i])
  492.     {
  493.       if (selstart <= start[i]) slstart = start[i]; else slstart = selstart;
  494.       if (selend >= start[i+1]) slend = start[i+1]-1; else slend = selend;
  495.       tc = str[slstart];
  496.       str[slstart] = '\0';
  497.       xsel = startx[i] + fmgetstrwidth(fnt,lines[i]);
  498.       str[slstart] = tc;
  499.       tc = str[slend];
  500.       str[slend] = '\0';
  501.       wsel = fmgetstrwidth(fnt,&(str[slstart]));
  502.       fl_rect(xsel,starty[i]-height,wsel,height,forecol);
  503.       cmov2(xsel,starty[i]-height+desc);
  504.       fl_color(backcol);
  505.       fmprstr(&(str[slstart]));
  506.       str[slend] = tc;
  507.     }
  508.   }
  509.  
  510.   /* Draw the cursor */
  511.   if (curspos >= 0)
  512.   {
  513.     i=0; while (start[i] <= curspos) i++;
  514.     i--;
  515.     tc = str[curspos];
  516.     str[curspos] = '\0';
  517.     tt = fmgetstrwidth(fnt,lines[i]);
  518.     str[curspos] = tc;
  519.     fl_rect(startx[i]+tt,starty[i]-height,2.,height,curscol);
  520.   }
  521.     
  522.   /* Restore the original string. */
  523.   for (i = 1; i < lnumb; i++)
  524.     str[start[i]-1] = NL;
  525.  
  526.   /* Reset clipping if required */
  527.   if (clip) fl_unset_clipping();
  528. }
  529.  
  530. /***
  531.   Next routine returns the position of the mouse in a string
  532. ***/
  533.  
  534. int fl_get_pos_in_string(
  535.   int horalign,        /* Horizontal alignment -1=left, 0=center, 1=right */
  536.   int vertalign,    /* Vertical alignment -1=bottom, 0=center, 1=top */
  537.   float x, float y, float w, float h,    /* Bounding box */
  538.   float size,        /* Font size */
  539.   int style,        /* Font style */
  540.   float xpos, float ypos, /* Position of the mouse */
  541.   char str[])        /* The (muli-line) string */
  542. {
  543.   int i;        /* counter */
  544.   char tc;        /* temporary character */
  545.   int start[1024];    /* start position of the lines */
  546.   int lnumb;        /* number of lines */
  547.   int theline;        /* number of line in which the mouse lies */
  548.   char *line;        /* line in which mouse lies */
  549.   float startx;        /* start x-coordinate of this line */
  550.   float width;        /* string width of this line */
  551.   fmfonthandle fnt;    /* font to be used */
  552.   fmfontinfo info;    /* info of the font */
  553.   float height;        /* height of the font */
  554.   float toppos;        /* y-coord of the top line */
  555.  
  556.   /* Check whether anything has to be done */
  557.   if (str == NULL || str[0] == '\0') return 0;
  558.  
  559.   /* Set the font to be used and get some info */
  560.   fnt = use_font(style,size);
  561.   if (fnt == NULL) return 0;
  562.   fmsetfont(fnt);
  563.   fmgetfontinfo(fnt,&info);
  564.   height = info.ysize;
  565.  
  566.   /* Split string into lines */
  567.   start[0] = 0;
  568.   lnumb = 1;
  569.   for (i = 0; str[i] != '\0'; i++)
  570.     if (str[i] == NL) start[lnumb++] = i+1;
  571.   start[lnumb] = i+1;
  572.  
  573.   /* Calculate line in which mouse lies */
  574.   if (vertalign == -1) toppos = y - lnumb*height;
  575.   if (vertalign ==  0) toppos = y + 0.5*h + 0.5*lnumb*height;
  576.   if (vertalign ==  1) toppos = y + h;
  577.   theline = (int) ((toppos - ypos)/height);
  578.   if (theline < 0) return 0;
  579.   if (theline >= lnumb) return strlen(str);
  580.   line = &(str[start[theline]]);
  581.   
  582.   /* Calculate start coordinate of the line */
  583.   tc = str[start[theline+1]-1];
  584.   str[start[theline+1]-1] = '\0';
  585.   width = fmgetstrwidth(fnt,line);
  586.   if (horalign == -1) startx = x;
  587.   if (horalign == 0)  startx = x + 0.5*(w-width);
  588.   if (horalign == 1)  startx = x + w - width;
  589.   str[start[theline+1]-1] = tc;
  590.  
  591.   for (i = start[theline]+1; i < start[theline+1]; i++)
  592.   {
  593.     tc = str[i];
  594.     str[i] = '\0';
  595.     if (xpos-startx <= fmgetstrwidth(fnt,line)) { str[i] = tc; return i-1;}
  596.     str[i] = tc;
  597.   }
  598.   return start[theline+1]-1;
  599. }
  600.  
  601. /***
  602.   Misselaneous text drawing routines
  603. ***/
  604.  
  605. void fl_drw_text_cursor(int align,float x,float y,float w,float h,
  606.              int c,float size,int style,char str[],int cc,int pos)
  607. /* Draws a (multi-line) text with a cursor. */
  608. {
  609.   int horalign,vertalign;
  610.   float height = fl_get_char_height(size,style);
  611.  
  612.   switch (align) {
  613.      case FL_ALIGN_LEFT:    horalign = -1; vertalign =  0; break;
  614.      case FL_ALIGN_RIGHT:    horalign =  1; vertalign =  0; break;
  615.      case FL_ALIGN_CENTER:    horalign =  0; vertalign =  0; break;
  616.      case FL_ALIGN_TOP:        horalign =  0; vertalign =  1; break;
  617.      case FL_ALIGN_BOTTOM:    horalign =  0; vertalign = -1; break;
  618.   }
  619.   fl_drw_string(horalign,vertalign,
  620.         x+0.5*height,y+0.25*height,w-height,h-0.5*height,
  621.         FALSE,
  622.         7,c,cc,
  623.         size,style,
  624.         pos,
  625.         0,-1,
  626.         str);
  627. }
  628.  
  629. void fl_drw_text(int align,float x,float y,float w,float h,
  630.           int c,float size,int style,char str[])
  631. /* Draws a text inside a box. */
  632. {
  633.   if (str == NULL || str[0] == '\0') return;
  634.   if (str[0] == '@') if (fl_draw_symbol(str,x,y,w,h,c)) return;
  635.   fl_drw_text_cursor(align,x,y,w,h,c,size,style,str,0,-1);
  636. }
  637.  
  638. void fl_drw_text_beside(int align,float x,float y,float w,float h,
  639.              int c,float size,int style, char str[])
  640. /* Draws a text besides a box. */
  641. {
  642.   if (str == NULL || str[0] == '\0') return;
  643.   if      (align == FL_ALIGN_LEFT)
  644.       fl_drw_text(FL_ALIGN_RIGHT,x-h,y,h,h,c,size,style,str);
  645.   else if (align == FL_ALIGN_RIGHT)
  646.       fl_drw_text(FL_ALIGN_LEFT,x+w,y,h,h,c,size,style,str);
  647.   else if (align == FL_ALIGN_TOP)
  648.       fl_drw_text(FL_ALIGN_BOTTOM,x,y+h,w,h,c,size,style,str);
  649.   else if (align == FL_ALIGN_BOTTOM)
  650.       fl_drw_text(FL_ALIGN_TOP,x,y-h,w,h,c,size,style,str);
  651.   else
  652.       fl_drw_text(FL_ALIGN_CENTER,x,y,w,h,c,size,style,str);
  653. }
  654.